package cn.yudao.ymcc.service.impl;

import cn.yudao.GlobleException;
import cn.yudao.ymcc.domain.PayFlow;
import cn.yudao.ymcc.domain.PayOrder;
import cn.yudao.ymcc.dto.AliPayNotifyMqDto;
import cn.yudao.ymcc.dto.AlipayNotifyDto;
import cn.yudao.ymcc.service.IAlipayNotifyService;
import cn.yudao.ymcc.service.IPayFlowService;
import cn.yudao.ymcc.service.IPayOrderService;
import cn.yudao.ymcc.utils.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AlipayNotifyServiceImpl implements IAlipayNotifyService {

    @Autowired
    private IPayOrderService payOrderService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private IPayFlowService payFlowService;

    /**
    * @Title: alipayNotify
    * @Description: 支付宝回调后的操作
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 10:50
    * @Parameters:
    * @Return
    */
    @Override
    public String alipayNotify(AlipayNotifyDto dto) {
        // 判断回调中支付的状态是否是完成支付
        AssertUtil.isTrue(dto.isTradeSuccess(),"支付异常");
        // 将dto转换为map类
        Map map = JSONObject.parseObject(JSON.toJSONString(dto), Map.class);
        // 检查支付签名
        try {
            Boolean aBoolean = Factory.Payment.Common().verifyNotify(map);
            if (!aBoolean){ // 签名校验失败
                return "success"; // 不需要再次发送支付回调信息了
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "error"; // 再次发送重新验证
        }
        // ===========================================================
        // 对参数合法性校验
        PayOrder payOrder = payOrderService.getPayOrder(dto.getOut_trade_no());
        String success = parameterVerfy(dto, payOrder); // 调用方法校验参数
        if (success != null){
            return success;
        }
        // ==========================================================
        // 修改支付单状态
        payOrder.setPayStatus(PayOrder.SUCCESS_STATUS);
        Date date = new Date();
        payOrder.setUpdateTime(date);
        // 添加流水 --- 调用方法给流水单赋值
        PayFlow payFlow = assignPayFlow(dto, payOrder, date);
        // 将对象装入map中
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("payOrder",payOrder);
        hashMap.put("payFlow",payFlow);
        // 使用mq发送事务消息
        // 创建发送对象--message
        AliPayNotifyMqDto aliDto = new AliPayNotifyMqDto(payOrder.getOrderNo(), payOrder.getExtParams());
        Message<AliPayNotifyMqDto> message = MessageBuilder.withPayload(aliDto).build();
        // 发送事务消息
        TransactionSendResult txOrderPay = rocketMQTemplate.sendMessageInTransaction(
                "txPayOrderCourse", // 事务组名
                "topic-aliPay:tags-aliPay", // 发送频道
                message, // 消费者消费内容
                hashMap // 执行本地事务需要得数据
        );
        // 判断是否正确
        LocalTransactionState state = txOrderPay.getLocalTransactionState(); // 执行本地事务状态
        SendStatus status = txOrderPay.getSendStatus(); // 执行本地事务状态
        // 判断本地事务是否执行成功
        if (state != LocalTransactionState.COMMIT_MESSAGE || status != SendStatus.SEND_OK){
            throw new GlobleException("发送异常");
        }

        return "success";
    }

    /**
    * @Title: assignPayFlow
    * @Description: 支付回调--给流水单对象赋值
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 20:16
    * @Parameters:
    * @Return
    */
    public PayFlow assignPayFlow(AlipayNotifyDto dto, PayOrder payOrder, Date date) {
        PayFlow payFlow = new PayFlow();
        payFlow.setNotifyTime(date); // 交易时间
        payFlow.setSubject(payOrder.getSubject()); // 标题
        payFlow.setOutTradeNo(dto.getOut_trade_no()); // 订单号
        payFlow.setTotalAmount(payOrder.getAmount()); // 金额
        payFlow.setTradeStatus(AlipayNotifyDto.TRADE_SUCCESS); // 成功
        payFlow.setPassbackParams(dto.getPassback_params());
        payFlow.setPaySuccess(payOrder.getPayStatus() == PayOrder.SUCCESS_STATUS); // 是否支付成功
        return payFlow;
    }

    /**
    * @Title: parameterVerfy
    * @Description: 支付回调中进行的参数合理性校验
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 20:12
    * @Parameters:
    * @Return
    */
    public String parameterVerfy(AlipayNotifyDto dto, PayOrder payOrder) {
        if (payOrder == null){ // 判断非空
            return "success";
        }
        if (payOrder.getPayStatus() != PayOrder.WAIT_STATUS){ // 判断状态是否为等待
            // 应该退款
            try {
                Factory.Payment.Common().refund(payOrder.getOrderNo(), dto.getTotal_amount()); // 退款
            } catch (Exception e) {
                log.info("退款异常--请及时处理");
                // 给管理员发送手机或者钉钉表明异常--走人工服务
                e.printStackTrace();
            }
            return "success";
        }
        if (new BigDecimal(dto.getTotal_amount()).compareTo(payOrder.getAmount()) !=0 ){ // 判断支付金额是否正确
            return "success";
        }
        return null;
    }

    /**
    * @Title: updatePayOrderInsertPayFlow
    * @Description: 修改PayOrder和新增PayFlow -- 本地事务
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 13:57
    * @Parameters:
    * @Return
    */
    @Override
    @Transactional
    public boolean updatePayOrderInsertPayFlow(Map<String, Object> map) {
        PayOrder payOrder = (PayOrder)map.get("payOrder");
        PayFlow payFlow = (PayFlow)map.get("payFlow");
        // 查询订单状态是否为待支付
        PayOrder payOrderTem = payOrderService.getPayOrder(payOrder.getOrderNo());
        AssertUtil.isTrue(payOrderTem.getPayStatus() == PayOrder.WAIT_STATUS,"订单异常");
        // 修改订单状态
        payOrderService.updateById(payOrder);
        // 添加流水
        payFlowService.insert(payFlow);
        return true;
    }
}
